package com.gitee.qdbp.jdbc.stream;

import java.util.Map;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.condition.DbWhere;
import com.gitee.qdbp.able.jdbc.ordering.Orderings;
import com.gitee.qdbp.jdbc.api.CrudDao;

/**
 * Where查询后续操作<br>
 * 后续操作有: delete / find|findFieldValue / count|groupCount / orderBy / paging / list|listFieldValues
 *
 * @author zhaohuihua
 * @version 20210529
 */
public class CrudOnAfterWhereByStream<T> extends CrudOnAfterOrderByStream<T> {

    CrudOnAfterWhereByStream(CrudDao<T> dao, DbWhere where) {
        super(dao, where, Orderings.NONE);
    }

    /**
     * 根据查询条件获取对象<br>
     * <pre>
    SysUser user = qdbcBoot.crudStream(SysUser.class)
        .where("id").equals("U00001")
            .and("userState").in(UserState.NORMAL, UserState.LOCKED)
            .end()
        .find();
     * </pre>
     * 
     * @return 实体对象
     */
    public T find() {
        return dao.find(where);
    }

    /**
     * 根据条件查询某个字段的值<br>
     * <pre>
    String deptCode = qdbcBoot.crudStream(SysUser.class)
        .where("id").equals("U00001")
            .and("userState").in(UserState.NORMAL, UserState.LOCKED)
            .end()
        .findFieldValue("deptCode", String.class);
     * </pre>
     * 
     * @param fieldName 指定字段名
     * @param valueClazz 字段值类型
     * @return 字段的值列表
     */
    public <V> V findFieldValue(String fieldName, Class<V> valueClazz) throws ServiceException {
        return dao.findFieldValue(fieldName, where, valueClazz);
    }

    /**
     * 根据条件统计实体数量<br>
     * <pre>
    int total = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .count();
     * </pre>
     * 
     * @return 数据数量
     */
    public int count() throws ServiceException {
        return dao.count(where);
    }

    /**
     * 根据条件分组统计实体数量<br>
     * <pre>
    Map&lt;String, Integer&gt; result = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .groupCount("userType");
    
    SELECT USER_TYPE, COUNT(*) FROM SYS_USER
        WHERE CREATE_TIME BETWEEN :1 AND :2
        AND (USER_CODE LIKE '%test%' OR REAL_NAME LIKE '%test%')
        AND DATA_STATE='E'
        GROUP BY USER_TYPE
     * </pre>
     * 
     * @param groupBy 分组条件
     * @return 分组统计结果
     */
    public Map<String, Integer> groupCount(String groupBy) throws ServiceException {
        return dao.groupCount(groupBy, where);
    }

    /**
     * 设置OrderBy条件<br>
     * <pre>
    List&lt;SysUser&gt; users = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .orderBy("createTime desc")
        .list();
     * </pre>
     * 
     * @param orderings OrderBy条件
     * @return 返回后续流式操作对象
     */
    public CrudOnAfterOrderByStream<T> orderBy(String orderings) {
        return orderBy(Orderings.of(orderings));
    }

    /**
     * 设置OrderBy条件<br>
     * <pre>
    List&lt;SysUser&gt; users = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .orderBy(orderings)
        .list();
     * </pre>
     * 
     * @param orderings OrderBy条件
     * @return 返回后续流式操作对象
     */
    public CrudOnAfterOrderByStream<T> orderBy(Orderings orderings) {
        return new CrudOnAfterOrderByStream<>(dao, where, orderings);
    }

    /**
     * 根据主键编号删除实体对象(逻辑删除)<br>
     * <pre>
    SysUser user = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .logicalDelete();
     * </pre>
     *
     * @return 删除行数
     * @throws ServiceException 删除失败
     */
    public int logicalDelete() throws ServiceException {
        return dao.logicalDelete(where);
    }

    /**
     * 根据主键编号删除实体对象(逻辑删除)<br>
     * <pre>
    SysUser user = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .logicalDelete(true, false);
     * </pre>
     *
     * @param fillUpdateParams 是否自动填充更新参数(修改人/修改时间等)
     * @param errorOnUnaffected 受影响行数为0时是否抛异常
     * @return 删除行数
     * @throws ServiceException 删除失败
     */
    public int logicalDelete(boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException {
        return dao.logicalDelete(where, fillUpdateParams, errorOnUnaffected);
    }

    /**
     * 根据主键编号删除实体对象(物理删除)<br>
     * <pre>
    SysUser user = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .physicalDelete();
     * </pre>
     *
     * @return 删除行数
     * @throws ServiceException 删除失败
     */
    public int physicalDelete() throws ServiceException {
        return dao.physicalDelete(where);
    }

    /**
     * 根据主键编号删除实体对象(物理删除)<br>
     * <pre>
    SysUser user = qdbcBoot.crudStream(SysUser.class)
        .where("userType").equals(1)
            .and("createTime").between(DateTools.addDay(now, -1), DateTools.addDay(now, +1))
            .and().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .end()
        .physicalDelete(true); // 受影响行数为0时抛异常
     * </pre>
     *
     * @param errorOnUnaffected 受影响行数为0时是否抛异常
     * @return 删除行数
     * @throws ServiceException 删除失败
     */
    public int physicalDelete(boolean errorOnUnaffected) throws ServiceException {
        return dao.physicalDelete(where, errorOnUnaffected);
    }
}
